package sms_kuailian

import (
	"bytes"
	"context"
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"net/http"
	"time"
)

type Client struct {
	cfg    *Config
	httpCL *http.Client
}

func New(cfg *Config) *Client {
	return &Client{
		cfg:    cfg,
		httpCL: &http.Client{Timeout: 5 * time.Second},
	}
}

func (c *Client) sign(ts string) string {
	s := c.cfg.AppKey + c.cfg.AppSecret + ts
	sum := md5.Sum([]byte(s))
	return hex.EncodeToString(sum[:])
}

func (c *Client) post(ctx context.Context, path string, in, out any) error {
	url := c.cfg.GateHost + path
	body, _ := json.Marshal(in)
	req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewReader(body))
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "application/json")

	resp, err := c.httpCL.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("http %d", resp.StatusCode)
	}
	return json.NewDecoder(resp.Body).Decode(out)
}

// 具体业务封装
func (c *Client) Send(ctx context.Context, req *SendReq) (*SendResp, error) {
	ts := fmt.Sprintf("%d", time.Now().UnixMilli())
	req.AuthReq = AuthReq{
		AppKey:    c.cfg.AppKey,
		AppCode:   c.cfg.AppCode,
		Sign:      c.sign(ts),
		Timestamp: ts,
	}
	var rsp SendResp
	if err := c.post(ctx, "/sms/batch/v1", req, &rsp); err != nil {
		return nil, err
	}
	return &rsp, nil
}

func (c *Client) Balance(ctx context.Context) (*BalanceResp, error) {
	ts := fmt.Sprintf("%d", time.Now().UnixMilli())
	in := AuthReq{
		AppKey:    c.cfg.AppKey,
		AppCode:   c.cfg.AppCode,
		Sign:      c.sign(ts),
		Timestamp: ts,
	}
	var out BalanceResp
	if err := c.post(ctx, "/sms/balance/v1", in, &out); err != nil {
		return nil, err
	}
	return &out, nil
}
